iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
Software Development

30 天精通 C 語言建置與除錯:從 Makefile 到 CMake 跨平台實戰系列 第 21

[Day 21] [Cmake]深入解析Cmake, CMakelist.txt, Makefile 的對應關係

  • 分享至 

  • xImage
  •  

Day 20的時候我們有提到利用cmakelist產生Makefile,並且透過產生的Makefile編譯出執行檔執行程式,今天我們要來一步一步解析昨天提到的CMakelist.txt以及下的指令一系列的對應關係...

由前面的文章我們可以知道Cmake是輔助生成Makefile的工具,在Day19的時候我們有提到Cmake的幾個常見的指令跟用途,今天我們就要結合前面幾篇的文章,綜合解讀一下Cmake的標準寫法。

首先~我們回到Day 20的這個CMakeLists.txt例子:
這個 CMakeLists.txt 主要是 描述 下面的資訊

  1. 宣告專案(名字、版本、語言)
  2. 設定一些全域參數(C 語言標準、輸出 compile_commands.json)
  3. 建一個靜態函式庫 dog_meme(由 src/dog_meme.c 編譯而來)
  4. 建一個可執行檔 app(主程式在 src/main.c),並且連結 dog_meme 函式庫
  5. 對 app 這個 target 設定編譯選項、巨集定義、include 路徑
  6. 定義安裝規則

但你可能會問:

不對呀?
cmake應該是用來產生makefile的工具,那Cmakelist.txt裡面為什麼沒有關於要用到 Makefile的建置資訊?.........
有Cmakelist.txt就可以建置了,
為什麼前面有提到 cmakelist.txt 跟 makefile是不同層級的工具?
/images/emoticon/emoticon04.gif

那我們這樣解釋好了... cmake, makefile, make 的層級關係其實是這樣的

最高層:CMake   (meta-build system / generator)
         ↳ 負責跨平台抽象,把 target 屬性轉換成對應 backend 語法

中層: 生成的檔案 (Makefile, build.ninja, .sln, .xcodeproj)
         ↳ 這些是 build description,描述怎麼建置

底層: Build tools (GNU Make, Ninja, MSBuild, Xcodebuild)
         ↳ 真正呼叫 gcc/clang/msvc 去編譯/連結

gnu make 的官網把make這樣定義

GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files.

Make 本身跟 Ninja 一樣是屬於 build system 專門來控制編譯的編譯過程/images/emoticon/emoticon33.gif

而CMake 算是 build system generator ,他不是直接控制編譯器編譯source code,而是編出build executor去控制編譯器執行編譯,主要可以理解成下面的幾個重點

Cmakelist.txt裡描述要編什麼、怎麼編
Cmake會根據"下指令 -G" 的資訊產生相對應的makefile 或是 Ninja,就是Day20的最後那行產生makefile的指令

cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug  # 產生Makefilie

而其實上面的指令可以有一系列的變化..../images/emoticon/emoticon06.gif (也太多...)

不同指令可以產生不同的 build system的工具,例如 makefile,Ninja...
下面整理了常見的用法範例

指令 說明
cmake -S . -B build 最基本用法-S . 表示來源(source)目錄是當前目錄(CMakeLists.txt 在這裡)。 -B build 表示輸出的「建置目錄」是 build/。 預設會用系統的 default generator(通常是 Unix Makefiles 或 Ninja,依環境而定)。
cmake -S . -B build -G "Unix Makefiles" /images/emoticon/emoticon33.gif(產生本系列鐵人競賽文中最常提到的makefile) 指定 generator 為「Unix Makefiles」。 → 會在 build/ 裡產生 Makefile,之後用 make 來編譯。
cmake -S . -B build -G "Ninja" 指定 generator 為 Ninja。 → 會在 build/ 裡產生 build.ninja,之後用 ninja 來編譯。 (Ninja 比 Make 快很多,常見於大型專案或 CI/CD pipeline)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug Day20中有提到的 指定 建置型態 為 Debug。 → 編譯時會加上 -g(debug symbols)、停用最佳化,方便除錯。 預設型態通常是空的(或 Release,依系統設定)。
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release 指定為 Release。 → 編譯時會加上 -O3(最佳化),不包含 debug symbols。 適合發佈執行檔。
cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo 介於 Release 和 Debug 之間。 → 加上最佳化 -O2,但仍保留 debug symbols。 適合邊測試效能邊除錯。
cmake -S . -B build -DCMAKE_BUILD_TYPE=MinSizeRel 最小體積模式。 → 加上 -Os,盡量壓縮程式大小。 常用於嵌入式或發佈極小安裝包。
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=arm-gcc-toolchain.cmake 指定 交叉編譯的工具鏈檔。 → 例如在 x86 機器上編 ARM 程式。 arm-gcc-toolchain.cmake 裡會寫明編譯器前綴、sysroot 等設定。
cmake --build build 執行建置。 CMake 會自動呼叫對應的工具: - 如果 generator 是 Makefile → 呼叫 make - 如果 generator 是 Ninja → 呼叫 ninja
cmake --install build --prefix ./dist 把建置結果安裝到指定路徑 ./dist。 (安裝規則在 CMakeLists.txt 裡用 install() 定義)。

上一篇
[Day 20] [make→cmake] 執行人生中第一個CmakeList
下一篇
[Day 22] [cmake] 深入了解Cmake指令與看懂CMakelist.txt
系列文
30 天精通 C 語言建置與除錯:從 Makefile 到 CMake 跨平台實戰24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言